/*
 * @Author       : LuHeQiu
 * @Date         : 2021-04-01 18:51:38
 * @LastEditTime : 2021-04-01 18:51:39
 * @LastEditors  : LuHeQiu
 * @Description  : 
 * @FilePath     : \User\task.c
 * @HomePage     : https://www.luheqiu.com
 */

/* Includes ------------------------------------------------------------------*/
#include "task.h"

/* Private variables ---------------------------------------------------------*/
TaskStack taskStack;

/**
  * @brief  Initializes the TaskSystem according to the default parameters.
  * @param  None
  * @retval None
  */
void InitTaskSystem(){
    
    /* initialize the task stack */
    
    taskStack.maxTaskNum=MAX_TASK_NUM;
    taskStack.resTaskNum=MAX_TASK_NUM;
    taskStack.maxTickNum=MAX_TICK_NUM;
    taskStack.resTickNum=MAX_TICK_NUM;
    
    /* Config TIM14 */
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	RCC_ClocksTypeDef RCC_Clocks;  //RCC时钟结构体
	NVIC_InitTypeDef NVIC_InitStructure;  //NVIC中断向量结构体
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE); 
	
	RCC_GetClocksFreq(&RCC_Clocks);		//获取系统时钟
	TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (RCC_Clocks.PCLK_Frequency / (1000/TASKSYSTEM_PERIOD*MAX_TICK_NUM*10) ) - 1;
	TIM_TimeBaseStructure.TIM_Period = 10-1;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure);
	
	/* Enable the TIM144 Update Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = TIM14_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	TIM_ClearFlag(TIM14, TIM_FLAG_Update);
	TIM_ITConfig(TIM14,TIM_IT_Update,ENABLE); //打开溢出中断
    
    TIM_Cmd(TIM14,DISABLE);
}

/**
  * @brief  Create a new task and add it to the taskStack.
  * @param  taskFunction: Provides a handle to a task function through which the system can execute a task.
  * @param  ticks: Determine how much time the task will take.
  * @param  period: Determine the execution period of the task.(ms)
  * @retval None
  */
uint8_t CreateTask( uint8_t (*taskFunction)(uint8_t),uint8_t ticks,uint16_t period){
    
    if(taskStack.resTaskNum<=0)return(1);               /* The maximum number of tasks has been exceeded */
    if(taskStack.resTickNum<=0)return(2);               /* The maximum number of ticks has been exceeded */
    
    for(uint8_t i=0;i<taskStack.maxTaskNum-taskStack.resTaskNum;i++){  
        if(taskStack.tasks[i].taskFunction==taskFunction){
            return(3);                                  /* This task is already in the taskStack         */
        }
    }  
    
    taskStack.tasks[taskStack.maxTaskNum-taskStack.resTaskNum].taskFunction=taskFunction;
    taskStack.tasks[taskStack.maxTaskNum-taskStack.resTaskNum].taskTicks=ticks;
    taskStack.tasks[taskStack.maxTaskNum-taskStack.resTaskNum].defaultPeriod=period;
    
    taskStack.tasks[taskStack.maxTaskNum-taskStack.resTaskNum].taskstate=waiting;
    taskStack.tasks[taskStack.maxTaskNum-taskStack.resTaskNum].cTaskPerid=period/TASKSYSTEM_PERIOD;
    
    taskStack.resTaskNum-=1;
    taskStack.resTickNum-=ticks;
    
    
    (*taskFunction)(0);
    
    return(0);
}

/**
  * @brief  Launch a task which in the taskStack
  * @param  taskFunction: Provides a handle to a task function through which the system can execute a task.
  * @retval None
  */
uint8_t RunningTask( uint8_t taskID,uint8_t* taskTicks){
    
    if(taskID>=(taskStack.maxTaskNum-taskStack.resTaskNum))return(1);    /* The task is not on the stack */

    (*taskTicks)=taskStack.tasks[taskID].taskTicks;
    taskStack.tasks[taskID].taskstate=running;
    
    return(0);
}

/**
  * @brief  Stop a task which in the taskStack
  * @param  taskFunction: Provides a handle to a task function through which the system can execute a task.
  * @retval None
  */
uint8_t StopTask(uint8_t (*taskFunction)(uint8_t)){
    
    for(uint8_t i=0;i<taskStack.maxTaskNum-taskStack.resTaskNum;i++){  
        if(taskStack.tasks[i].taskFunction==taskFunction){
            taskStack.tasks[i].taskstate=release;
            return 0;
        }
    }
    return 1;
}

/**
  * @brief  Launch the task scheduling system
  * @param  None
  * @retval None
  */
void LaunchTaskSchedule(){
    TIM_Cmd(TIM14,ENABLE);
}

/**
  * @brief  Close the task scheduling system
  * @param  None
  * @retval None
  */
void CloseTaskSchedule(){
    TIM_Cmd(TIM14,DISABLE);
}

/**
  * @brief  Task polling
  * @param  None
  * @retval None
  */
void TaskScheduleLoop(void){
    
    static uint8_t taskID=0;
    static uint8_t taskticks=0;
    static uint8_t periodticks=0;
    static uint8_t isFree=0;
        
    if(taskID>=taskStack.maxTaskNum-taskStack.resTaskNum)taskID=0;
    
    
    switch(taskStack.tasks[taskID].taskstate){
        case sleep:   // 0 1 2 3
        {
            if(isFree){
                taskID++;
            }
            break;
        }
        
        case ready:
        {
            if(isFree){
                RunningTask(taskID,&taskticks);
                isFree=0;
            }
            break;
        }
            
        case running:
        {
            uint8_t res = (*taskStack.tasks[taskID].taskFunction)(1);
            if( res == 0 ){
                taskStack.tasks[taskID].taskstate=waiting;
                taskStack.tasks[taskID].cTaskPerid=taskStack.tasks[taskID].defaultPeriod/TASKSYSTEM_PERIOD;
            }else if(res == 3){
                taskStack.tasks[taskID].taskstate=release;
            }
            if( taskticks==0 )
                taskStack.tasks[taskID].taskstate=waiting;
                isFree=1;
            break;
        }
        
        case waiting:
        {
            if(isFree){
                if(taskID<taskStack.maxTaskNum-taskStack.resTaskNum-1)   // 0 1     :2
                    taskID++;
                else
                    taskID=0;
            }
            break;
        }
        
        case release:    //  0  x  2  3
        {
            uint8_t releasedTicks=taskStack.tasks[taskID].taskTicks;
            
            for(uint8_t i=taskID;i<taskStack.maxTaskNum-taskStack.resTaskNum;i++){  
                taskStack.tasks[i]=taskStack.tasks[i+1];
            }
            
            taskStack.resTickNum+=releasedTicks;
            taskStack.resTaskNum+=1;
            isFree=1;
        }
            
    }
    
   
        
    if(taskticks>0)
        taskticks--;
    else
        isFree=1;
        
    
    periodticks++;
    if(periodticks==MAX_TICK_NUM){
        for(uint8_t i=0;i<taskStack.maxTaskNum-taskStack.resTaskNum;i++){
            if(taskStack.tasks[i].taskstate==waiting){
                
                if(taskStack.tasks[i].cTaskPerid>0){
                    taskStack.tasks[i].cTaskPerid--;
                }
                
                if(taskStack.tasks[i].cTaskPerid==0){
                    taskStack.tasks[i].taskstate=ready;
                }

            }
        }
        periodticks=0;
    }
    
}



/*以下为中断服务程序*/
void TIM14_IRQHandler(void)
{
	 //是否有更新中断
	if(TIM_GetITStatus(TIM14,TIM_IT_Update) != RESET)
	{
		 //清除中断标志
		TIM_ClearITPendingBit(TIM14,TIM_IT_Update); 
		//处理中断
		TaskScheduleLoop();
	}	
}
